package cc.iotkit.manager.service.impl;

import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtils;
import cc.iotkit.data.system.ISysConfigData;
import cc.iotkit.manager.dto.bo.map.MapFenceBo;
import cc.iotkit.manager.dto.bo.map.MapTrackBo;
import cc.iotkit.manager.service.IMapService;
import cc.iotkit.manager.task.AnalysisFence;
import cc.iotkit.model.map.MapFence;
import cc.iotkit.model.system.SysConfig;
import cn.hutool.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MapServiceImpl implements IMapService {
    private static Logger logger = LoggerFactory.getLogger(MapServiceImpl.class);
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //
    private String TRSEARCH=" https://tsapi.amap.com/v1/track/terminal/trsearch";
    private String CREATE_TERMINAL="https://tsapi.amap.com/v1/track/terminal/add";
    private String CREATE_TRACE="https://tsapi.amap.com/v1/track/trace/add";

    private String UPLOAD_TRACE="https://tsapi.amap.com/v1/track/point/upload";
    private String CREATE_CIRCLE= "https://tsapi.amap.com/v1/track/geofence/add/circle";
    private String CREATE_POLYGON= "https://tsapi.amap.com/v1/track/geofence/add/polygon";
    private String CREATE_POLYLINE= "https://tsapi.amap.com/v1/track/geofence/add/polyline";
    private String CREATE_DISTRICT= "https://tsapi.amap.com/v1/track/geofence/add/district";
    private String UPDATE_CIRCLE= "https://tsapi.amap.com/v1/track/geofence/update/circle";
    private String UPDATE_POLYGON= "https://tsapi.amap.com/v1/track/geofence/update/polygon";
    private String UPDATE_POLYLINE= "https://tsapi.amap.com/v1/track/geofence/update/polyline";
    private String UPDATE_DISTRICT= "https://tsapi.amap.com/v1/track/geofence/update/district";
    private String DELETE_FENCE="https://tsapi.amap.com/v1/track/geofence/delete";
    private String BIND_FENCE_TERMINAL="https://tsapi.amap.com/v1/track/geofence/terminal/bind";
    private String UNBIND_FENCE_TERMINAL="https://tsapi.amap.com/v1/track/geofence/terminal/unbind";
    private String FENCE_LOCATION_STATUS="https://tsapi.amap.com/v1/track/geofence/status/location";
    private String HW_LOCATION="https://apilocate.amap.com/position";

    private String GET_LASTPOINT="https://tsapi.amap.com/v1/track/terminal/lastpoint";
    @Value("${amap.webservice.key}")
    private String ak;

    @Value("${amap.webservice.sid}")
    private String serviceId;

    @Autowired
    private ISysConfigData sysConfigData;

    /**
     * 创建终端
     * @return
     */
    public String createTerminal(String deviceId){
        try {
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("name", deviceId);
            String res = HttpUtil.post(CREATE_TERMINAL, paramValues);
            Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
            if (map.get("errcode").toString().equals("10000")) {
                Map<String, Object> data= (Map<String, Object>)map.get("data");
                return data.get("tid").toString();
            } else {
                throw new BizException(map.get("errmsg").toString());
            }
        }catch (Exception e){
            throw new BizException(e.getMessage());
        }
    }
    /**
     * 查询终端
     * @return
     */
    public List<Map<String, Object>> getTerminal(String deviceId){
        try {
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("name", deviceId);
            String res = HttpUtil.get("https://tsapi.amap.com/v1/track/terminal/list", paramValues);
            Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
            if (map.get("errcode").toString().equals("10000")) {
                if(map.get("data")!=null) {
                    Map<String, Object> data = (Map<String, Object>) map.get("data");
                    return (List<Map<String, Object>>)data.get("results");
                }
                return new ArrayList<>();
            } else {
                throw new BizException(map.get("errmsg").toString());
            }
        }catch (Exception e){
            throw new BizException(e.getMessage());
        }
    }

    /**
     * 创建轨迹
     * @param tid
     * @return
     */
    public int createTrace(String deviceId,String tid){
        try {
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("tid", tid);
            paramValues.put("trname",deviceId);
            String res = HttpUtil.post(CREATE_TRACE, paramValues);
            Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
            if (map.get("errcode").toString().equals("10000")) {
                Map<String, Object> data= (Map<String, Object>)map.get("data");
                return Integer.valueOf(data.get("trid").toString());
            } else {
                throw new BizException(map.get("errmsg").toString());
            }
        }catch (Exception e){
            throw new BizException(e.getMessage());
        }
    }

    public boolean uploadPoints(String tid,int trid,List<Map<String,Object>> points){
        try {
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("tid", tid);
            paramValues.put("trid", trid);
            paramValues.put("points", JsonUtils.toJsonString(points));
            String res = HttpUtil.post(UPLOAD_TRACE, paramValues);
            Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
            if (map.get("errcode").toString().equals("10000")) {
               return true;
            } else {
                logger.error(map.get("errmsg").toString());
                //throw new BizException(map.get("errdetail").toString());
            }
        }catch (Exception e){
            logger.error(e.getMessage());
            //throw new BizException(e.getMessage());
        }
        return false;
    }

    /***
     * 查询某 设备 的实时位置，支持纠偏
     * @return
     */
    public Map<String,Object> getLatestPoint(String tid,int trid){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("tid", tid);
        paramValues.put("trid", trid);
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        //是否进行轨迹纠偏
        paramValues.put("correction", "n");
        String res= HttpUtil.get(GET_LASTPOINT,paramValues);
        Map<String, Object> map=(Map<String, Object>) JsonUtils.parseMap(res);
        if (map.get("errcode").toString().equals("10000")) {
            Map<String, Object> data= (Map<String, Object>)map.get("data");
            return  data;
        } else {
            logger.error(map.get("errmsg").toString());
            //throw new BizException(map.get("errmsg").toString());
            return null;
        }
    }

    /**
     * 查询行驶距离
     * @return
     */
    public Float getDistance(Long startTime,Long endTime,String tid,int trid){
        try {
            SysConfig config=  sysConfigData.findByConfigKey("geo.correction");
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("tid", tid);
            paramValues.put("trid", trid);
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("ispoints",0);
            paramValues.put("starttime", startTime);
            paramValues.put("endtime", endTime);
            paramValues.put("correction",config.getConfigValue());// "denoise=1,mapmatch=1,attribute=1,threshold=100,mode=driving");


            String res = HttpUtil.get(TRSEARCH, paramValues);
            Map<String, Object> map = JsonUtils.parseMap(res);

            if (map.get("errcode").toString().equals("10000")) {
                Map<String, Object> data= (Map<String, Object>)map.get("data");
                if(data!=null) {
                    List<Map<String, Object>> tracks = (List<Map<String, Object>>) data.get("tracks");
                    Map<String, Object> track = tracks.get(0);
                    return Float.valueOf(track.get("distance").toString());
                }
                else
                    return 0f;
            } else {
                logger.error(map.get("errmsg").toString());
                //throw new BizException(map.get("errmsg").toString());
            }
        }catch (Exception e){
            logger.error(e.getMessage());
            //throw new BizException(e.getMessage());
        }
        return null;
    }

    /**
     * 轨迹查询与纠偏
     * @return
     */
    public Map<String,Object> getTrack(MapTrackBo bo){
        try {
            int page =1;
            int pageSize=999;
            Map<String,Object> results=new HashMap<>();
            List<LinkedHashMap<String,Object>> points=new ArrayList<>();
            SysConfig config=  sysConfigData.findByConfigKey("geo.correction");
            Map<String, Object> paramValues = new HashMap<>();
            paramValues.put("tid", bo.getAmapTid());
            paramValues.put("key", this.ak);
            paramValues.put("sid", this.serviceId);
            paramValues.put("starttime", formatter.parse(bo.getStartTime()).getTime() );
            paramValues.put("endtime", formatter.parse(bo.getEndTime()).getTime());
            paramValues.put("correction",config.getConfigValue());// "denoise=1,mapmatch=1,attribute=1,threshold=100,mode=driving");
            //默认两点间距离超过5公里时认为点间距过远，可采用如下两种策略进行轨迹和里程的补充。
            //参数如下：
            //0：代表用直线连接方式进行补点计算；
            //1：代表用correction的mode方式进行补点计算，当前只开放了driving。
            paramValues.put("recoup", 0);
            //gap参数用来指定触发recoup参数生效的点间距，默认为5公里，最小50米，最大10公里，单位：米。
            paramValues.put("gap", 50);
            paramValues.put("page", page);
            paramValues.put("pagesize", pageSize);

            points=getHisTrack(paramValues,points,page,pageSize);


            results.put("points",points);
            return results;
        }catch (ParseException e){
            throw new BizException(e.getMessage());
        }
    }
    //合并所有分页历史轨迹
    public List<LinkedHashMap<String,Object>> getHisTrack(Map<String, Object> paramValues,List<LinkedHashMap<String,Object>> points, int page,int pageSize){
        String res = HttpUtil.get(TRSEARCH, paramValues);
        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (map.get("errcode").toString().equals("10000")) {
            Map<String, Object> data = (Map<String, Object>) map.get("data");
            if(data==null) return points;
            LinkedHashMap<String,Object> track=(LinkedHashMap)((ArrayList)((Map<String, Object>)map.get("data")).get("tracks")).get(0);
            //总轨迹数量
            Integer counts=Integer.valueOf(track.get("counts").toString());
            List<LinkedHashMap<String,Object>> pos= (ArrayList)track.get("points");
            points.addAll(pos);
            //判断轨迹是否加载完成
            if(counts>points.size()){
                page++;
                this.getHisTrack(paramValues,points,page,pageSize);
            }
        }

        return points;
    }
    /**
     * 获取用户今日实际公里数
     * @return
     */
    public Map<String,Object> getTodayUserActualDistance(){
        try{

           Long startTime= formatter.parse(LocalDate.now().toString()+" 00:00:00").getTime()/1000;
            Long endTime=new Date().getTime()/1000;

            Map<String, Object> paramValues=new HashMap<>();
            paramValues.put("starttime",startTime);
            paramValues.put("endtime",endTime.toString());

            return null;//this.getDistance(paramValues);
        }
        catch (Exception e){
            throw new BizException(e.getMessage());
        }
    }

    /**
     * 创建圆形围栏
     * @param bo
     * @return
     */
    public boolean createFenceCircle(MapFenceBo bo){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("name", bo.getFenceName());
        paramValues.put("desc", bo.getFenceDesc());

        String res = "";
        switch (bo.getFenceType()){
            case "circle":
                paramValues.put("center", bo.getCenter());
                paramValues.put("radius", bo.getRadius());
                res = HttpUtil.post(CREATE_CIRCLE, paramValues);
                break;
            case "polygon":
                paramValues.put("points", bo.getPoints());
                res = HttpUtil.post(CREATE_POLYGON, paramValues);
                break;
            case "polyline":
                paramValues.put("points", bo.getPoints());
                paramValues.put("bufferradius", bo.getBufferradius());
                res = HttpUtil.post(CREATE_POLYLINE, paramValues);
                break;
            case "district":
                paramValues.put("adcode", bo.getAdcode());
                res = HttpUtil.post(CREATE_DISTRICT, paramValues);
                break;
            default:
                break;
        }

        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (map.get("errcode").toString().equals("10000")) {
            Map<String, Object> data= (Map<String, Object>)map.get("data");
            String gfid= data.get("gfid").toString();

            bo.setGfid(Integer.valueOf(gfid));
        } else {
            throw new BizException(map.get("errmsg").toString());
        }
        return true;
    }

    /**
     * 更新圆形围栏
     * @param bo
     * @return
     */
    public boolean updateFenceCircle(MapFenceBo bo){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("gfid", bo.getGfid());
        paramValues.put("name", bo.getFenceName());
        paramValues.put("desc", bo.getFenceDesc());

        String res = "";
        switch (bo.getFenceType()){
            case "circle":
                paramValues.put("center", bo.getCenter());
                paramValues.put("radius", bo.getRadius());
                res = HttpUtil.post(UPDATE_CIRCLE, paramValues);
                break;
            case "polygon":
                paramValues.put("points", bo.getPoints());
                res = HttpUtil.post(UPDATE_POLYGON, paramValues);
                break;
            case "polyline":
                paramValues.put("points", bo.getPoints());
                paramValues.put("bufferradius", bo.getBufferradius());
                res = HttpUtil.post(UPDATE_POLYLINE, paramValues);
                break;
            case "district":
                paramValues.put("adcode", bo.getAdcode());
                res = HttpUtil.post(UPDATE_DISTRICT, paramValues);
                break;
            default:
                break;
        }

        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (!map.get("errcode").toString().equals("10000")) {
            throw new BizException(map.get("errmsg").toString());
        }
        return true;
    }

    /**
     * 更新圆形围栏
     * @param gfids
     * @return
     */
    public boolean deleteFence(String  gfids) {
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("gfids", gfids);
        String res = HttpUtil.post(DELETE_FENCE, paramValues);

        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (!map.get("errcode").toString().equals("10000")) {
            throw new BizException(map.get("errmsg").toString());
        }
        return true;
    }

    /**
     *增加监测对象
     * @param gfid 围栏id
     * @param tids 终端id
     * @return
     */
    public boolean bindFenceTerminal(Integer gfid, String tids){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("gfid", gfid);
        paramValues.put("tids", tids);
        String res = HttpUtil.post(BIND_FENCE_TERMINAL, paramValues);

        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (!map.get("errcode").toString().equals("10000")) {
            throw new BizException(map.get("errmsg").toString());
        }
        return true;
    }

    /**
     *删除监测对象
     * @param gfid 围栏id
     * @param tids 终端id
     * @return
     */
    public boolean unbindFenceTerminal(Integer gfid, String tids){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("gfid", gfid);
        paramValues.put("tids", tids);
        String res = HttpUtil.post(UNBIND_FENCE_TERMINAL, paramValues);

        Map<String, Object> map = (Map<String, Object>) JsonUtils.parseMap(res);
        if (!map.get("errcode").toString().equals("10000")) {
            throw new BizException(map.get("errmsg").toString());
        }
        return true;
    }

    /**
     * 查询指定坐标与围栏关系
     * @param location x,y坐标
     * @param gfids  围栏的唯一标识，支持一次传入多个，以","分割；
     * @return
     */
    public List<Map<String,Object>> findFenceStatus(String location, String gfids){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("sid", this.serviceId);
        paramValues.put("location", location);
        paramValues.put("gfids", gfids);
        String res = HttpUtil.get(FENCE_LOCATION_STATUS, paramValues);

        Map<String, Object> map = JsonUtils.parseMap(res);
        if (map.get("errcode").toString().equals("10000")) {
            Map<String, Object> data= (Map<String, Object>)map.get("data");
            List<Map<String,Object>> results= (List<Map<String, Object>>) data.get("results");
            return results;
        } else {
            //throw new BizException(map.get("errmsg").toString());
            logger.error(map.get("errmsg").toString());
            return null;
        }
    }

    /***
     * 获取智能硬件定位
     * @param params
     * @return
     */
    public Map<String,Object> getHWLocation(Map<String,Object> params){
        Map<String, Object> paramValues = new HashMap<>();
        paramValues.put("key", this.ak);
        paramValues.put("accesstype", params.get("accesstype"));
        paramValues.put("imei", params.get("imei"));
        paramValues.put("mmac", params.get("mmac"));
        paramValues.put("macs", params.get("macs"));
        String res = HttpUtil.get(HW_LOCATION, paramValues);

        Map<String, Object> map = JsonUtils.parseMap(res);
        if (map.get("infocode").toString().equals("10000")) {
            Map<String, Object> data= (Map<String, Object>)map.get("result");
            if(data.get("type").toString().equals("0"))
                return null;
            return data;
        } else {
            //throw new BizException(map.get("errmsg").toString());
            logger.error(map.get("errmsg").toString());
            return null;
        }
    }
}
